<!--
 * @Author: 李金深 2896583081@qq.com
 * @Date: 2023-06-25 10:33:19
 * @LastEditors: 李金深 2896583081@qq.com
 * @LastEditTime: 2023-06-27 14:09:35
 * @FilePath: /com.huizhouyiren.web.d0101/src/components/virtualList/virtualList.vue
 * @Description: 虚拟列表组件
-->
<script setup>
import { ref, watch, onMounted } from "vue"
import { throttle } from '@/utils/tools'

const props = defineProps({
    itemHeight: { // 每条数据的高度
        require: true,
        default: 100
    },
    showNum: {  //每次加载到可视区域的数量，itemHeight X showNum 要可视区域高度 ，否则页面滚动不了。
        require: true,
        default: 12
    },
    sourceData: {  // 源数据数组
        require: true,
        default: [],
    }

})

let scrollBox = ref(null)

let showList = ref([]) // 可视区域显示的数据
let top = ref(0) //偏移量
let scrollTop = ref(0) //卷起的高度
let startIndex = ref(0)//可视区域第一条数据的索引
let endIndex = ref(0) //可视区域最后一条数据后面那条数据的的索引，因为后面要用slice(start,end)方法取需要的数据，但是slice规定end对应数据不包含在里面	
let scrollHeight = ref([]) // 滚动的内容高度


/**
 * @description: 计算可视区域数据
 * @return {*}
 */
const getShowList = () => {
    startIndex.value = Math.floor(scrollTop.value / props.itemHeight); //可视区域第一条数据的索引
    endIndex.value = startIndex.value + props.showNum; //可视区域最后一条数据的后面那条数据的索引
    showList.value = props.sourceData.slice(startIndex.value, endIndex.value) //可视区域显示的数据，即最后要渲染的数据。实际的数据索引是从this.startIndex到this.endIndex-1
    top.value = scrollTop.value - (
        scrollTop.value % props.itemHeight); //在这需要获得一个可以被itemHeight整除的数来作为item的偏移量，这样随机滑动时第一条数据都是完整显示的
}

/**
 * @description: 设置滚动高度
 * @param {*} scrollTopValue
 * @return {*}
 */
const setTop = (scrollTopValue) => {
    scrollTop.value = scrollTopValue
    getShowList()
}

defineExpose({ setTop })


watch(() => { return props.sourceData }, () => {
    scrollHeight.value = props.sourceData.length * props.itemHeight
    getShowList()
}, {
    deep: true,
    immediate: true
})

onMounted(() => {
    scrollBox.value.addEventListener('scroll', (e) => {
        throttle(() => {
            scrollTop.value = e.target.scrollTop
            getShowList()
        }, 50)
    })
})

</script>
<template>
    <div style="height: 100%;width: 100%;">
        <div class="relative scroll_box" style="height: 100%;width: 100%;overflow-y: scroll;" ref="scrollBox">
            <div :style="{ 'top': `${top}px` }" style="width: 100%;position:absolute" class="left-0">
                <div class="flex items-center w-full" v-for="(item, index) in showList" :key="item.id + '' + index"
                    :style="{ height: itemHeight + 'px' }">
                    <slot :item="item"></slot>
                </div>
            </div>
        </div>
    </div>
</template>
<style>
.scroll_box::-webkit-scrollbar {
    height: 0;
    width: 0;
    color: transparent;
}
</style>
